<?php
namespace Destroyer\Http\Requests;

use Illuminate\Validation\ValidationException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

use Destroyer\Models\User;
// use App\Admin\Models\LoginRecord;
use App\Admin\Admin;

use PragmaRX\Google2FA\Google2FA;

class LoginRequest extends FormRequest
{

    protected $stopOnFirstFailure = false;

    protected User $user_model;

    public function rules(): array
    {
        return [
            'username' => 'required|between:5,50',
            'password' => 'required|between:6,20',
            'code' => 'sometimes|nullable|integer|digits:6',
        ];
    }

    public function attributes()
    {
        return [
            'username' => '账号',
            'password' => '密码',
            'code' => '双因素令牌',
        ];
    }

    public function messages()
    {
        return [
            'username.required' => ':attribute不能为空',
            'username.regex'    => '仅支持使用电子邮箱或手机号登录',

            'password.required' => ':attribute不能为空',
            'password.between' => ':attribute长度不符合要求，请检查是否正确',
            'password.regex'   => ':attribute错误',

            'code' => '双因素令牌错误',
        ];
    }

    public function loginNameIsEmail()
    {
        return filter_var($this->input('username'), FILTER_VALIDATE_EMAIL) ? true : false ;
    }

    public function getUserModel()
    {
        $username = $this->input('username');

        if( !$this->loginNameIsEmail() ){
            $user_model = User::where('mobile', $username)->first();
        }else{
            $user_model = User::where('email', $username)->first();
        }

        if( !$user_model ){
            throw ValidationException::withMessages(['username' => '账号不存在']);
        }

        return $this->user_model = $user_model;
    }

    public function comparePassword()
    {
        // $this->user_model->password = 123456;
        // $this->user_model->save();
        if( empty($this->user_model->password) ){
            throw ValidationException::withMessages(['password' => '该账户未设置密码，请联系管理员']);
        }
        if( !Hash::check($this->input('password'), $this->user_model->password) ){
            throw ValidationException::withMessages(['password' => '密码错误']);
        }
    }

    public function verify2FA($userModel)
    {
        $code = $this->input('code');
        if( $userModel->hasEnabledTwoFactorAuthentication() ){
            if( empty($code) ){
                throw ValidationException::withMessages(['code' => '你的账号已设置双因素认证，请输入令牌']);
            }

            $google2fa = new Google2FA();
            if( !$google2fa->verifyKey($userModel->two_factor_secret, $code) ){
                throw ValidationException::withMessages(['code' => '双因素令牌未通过认证']);
            }
        }
    }

    public function authenticate()
    {
        // 读取用户
        $this->getUserModel();

        // 对比密码
        $this->comparePassword($this->user_model);

        // 双因素认证
        $this->verify2FA($this->user_model);
    }

    public function record()
    {
        if( $this->user_model ){
            $this->user_model->login_ip = $this->ip();
            $this->user_model->login_time = now();
            $this->user_model->save();
        }

        $loginRecord = new LoginRecord();
        $loginRecord->user_id       = $this->user_model->id;
        $loginRecord->ip_address    = $this->ip();
        $loginRecord->location      = Admin::location($this->ip());
        $loginRecord->user_agent    = $this->header('User-Agent');
        $loginRecord->device_id     = '';
        $loginRecord->result_status = 'Success';
        $loginRecord->login_time    = now();
        $loginRecord->save();
    }

    /**
     * 这里使用对称加密生成token，可以有效避免重复
     * token储存在redis中，类session模式
     * 不直接使用jwt是因为后台与前台业务不同，后台需要频繁踢人等情况
     */
    public function generateToken()
    {
        try {
            $token = Str::random(64);

            DB::table('system_user_session')->insert([
                'id'            => $token,
                'user_id'       => $this->user_model->id,
                'ip_address'    => $this->ip(),
                'user_agent'    => $this->header('User-Agent'),
                'last_activity' => now(),
            ]);

            // 储存token
            Redis::set($token, $this->user_model->id);

            return $token;

        } catch (\Illuminate\Database\UniqueConstraintViolationException $e) {
            return null;
        }
    }

}
